package cn.funeralobjects.util;

import cn.funeralobjects.util.executor.GlobalPoolExecutor;

import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.LongSupplier;

/**
 * 时间工具类，主要利用多线程解决高并发下优化获取“当前时间”的方案
 *
 * @author FuneralObjects
 * Create date: 2020/4/16 3:25 PM
 */
public class TimeUtils {
    private static GlobalPoolExecutor TIME_EXECUTOR = new GlobalPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy());
    private static AtomicBoolean RUNNING = new AtomicBoolean(false);
    private static AtomicLong CURRENT = new AtomicLong(0L);
    /**
     * 默认获取时间间隔为 100ms
     */
    private static Long DEFAULT_INTERVAL = 100L;

    /**
     * 开始执行线程获取时间线程
     */
    public synchronized static void startRunning() {
        startRunning(DEFAULT_INTERVAL);
    }

    /**
     * 开始执行线程获取时间线程
     *
     * @param interval 每次获取时间的线程间隔
     */
    public synchronized static void startRunning(long interval) {
        startRunning(System::currentTimeMillis, interval);

    }

    /**
     * 开始执行线程获取时间线程
     *
     * @param getCurrent 自定义获取时间方式
     */
    public synchronized static void startRunning(LongSupplier getCurrent) {
        startRunning(getCurrent, DEFAULT_INTERVAL);
    }

    /**
     * 开始执行线程获取时间线程
     *
     * @param getCurrent 自定义获取时间方式
     * @param interval   每次获取时间的线程间隔
     */
    @SuppressWarnings("InfiniteLoopStatement")
    public synchronized static void startRunning(LongSupplier getCurrent, long interval) {
        if (RUNNING.get()) {
            throw new RuntimeException("The time thread already exists!");
        }
        TIME_EXECUTOR.execute(() -> {
            while (true) {
                CURRENT.set(getCurrent.getAsLong());
                try {
                    Thread.sleep(interval);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        RUNNING.set(true);
    }

    /**
     * 判断线程是否在执行
     *
     * @return true - 执行
     */
    public static boolean isRunning() {
        return RUNNING.get();
    }

    /**
     * 获取当前的时间
     *
     * @return long 格式时间
     */
    public static long getCurrent() {
        return CURRENT.get();
    }

    /**
     * 获取当前时间
     *
     * @return date 格式时间
     */
    public static Date getCurrentDate() {
        return new Date(CURRENT.get());
    }
}
